package ai.esc.speedy.admin.user.infrastructure.jwt;

import ai.esc.speedy.admin.user.infrastructure.shiro.SecurityConsts;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Rubin
 * @version v1 2020/2/27 16:36
 */
@Component
public class JwtUtil {

    @Autowired
    public JwtProperties jwtProperties;

    /**
     * 校验token是否正确
     *
     * @param token 密钥
     * @return 是否正确
     */
    public boolean verify(String token, JwtUserInfo userInfo) {
        try {
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecretKey());
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(SecurityConsts.ACCOUNT, userInfo.getAccount())
                    .withClaim("passportId", userInfo.getPassportId())
                    .withClaim("userId", userInfo.getUserId())
                    //.withClaim("userData", userInfo.getUserData())
                    .build();
            //效验TOKEN
            verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    public boolean verifyRefreshToken(String token, String account) {
        try {
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecretKey());
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(SecurityConsts.ACCOUNT, account)
                    .withClaim("type", "RefreshToken")
                    .build();
            //效验TOKEN
            verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }


    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public JwtUserInfo getJwtUserInfo(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return new JwtUserInfo(
                    jwt.getClaim(SecurityConsts.ACCOUNT).asString(),
                    jwt.getClaim("passportId").asString(),
                    jwt.getClaim("userId").asString(),
                    jwt.getClaim("userData").asString());
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得Token中的信息
     *
     * @param token
     * @param claim
     * @return
     */
    public String getClaim(String token, String claim) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claim).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名
     *
     * @param userInfo 用户信息
     * @return 加密的token
     */
    public String sign(JwtUserInfo userInfo) throws Exception {
        Date date = new Date(System.currentTimeMillis() + jwtProperties.getRefreshTokenExpireTime() * 60 * 1000);
        Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecretKey());

        if (userInfo == null) {
            throw new Exception("JwtUserInfo is not null!");
        }
        // 附带userInfo信息
        return JWT.create()
                .withClaim(SecurityConsts.ACCOUNT, userInfo.getAccount())
                .withClaim("passportId", userInfo.getPassportId())
                .withClaim("userId", userInfo.getUserId())
                .withClaim("userData", userInfo.getUserData())
                .withExpiresAt(date)
                .sign(algorithm);

    }

    public Map<String, String> getToken(JwtUserInfo userInfo) throws Exception {
        Map<String, String> map = new HashMap<>(4);
        map.put("access_token", sign(userInfo));
        map.put("refresh_token", getRefreshToken(userInfo.getAccount()));

        return map;
    }

    private String getRefreshToken(String account) {
        Date date = new Date(System.currentTimeMillis() + jwtProperties.getRefreshTokenExpireTime() * 60 * 1000);
        Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecretKey());
        return JWT.create()
                .withClaim(SecurityConsts.ACCOUNT, account)
                .withClaim("type", "RefreshToken")
                .withExpiresAt(date).sign(algorithm);

    }

}